#include <fstream>
#include <cstdio>

#include "LinearSystem.h"
#include "Chronometer.h"

int main(int argc, char *argv[])
{
    Chronometer c;
    int method = SEQUENTIAL;

    /* Recupera o método */
    if(argc >= 3)
        method = atoi(argv[2]);

    /* Inicializa o MPI quando for paralelo */
    if(method == PARALLEL)
        Manager::init();

    /* Número de argumentos diferente de 3 */
    if(argc != 3)
    {
        if(HAS_TO_PRINT(method))
            cerr << "Usage mode: " << argv[0] << " <linear system's filename> " <<
                    "<method: 1-sequential 2-parallel>" << endl;
        return EXIT_FAILURE;
    }

    /* Arquivo de entrada */
    ifstream is(argv[1]);
    if(!is.is_open())
    {
        if(HAS_TO_PRINT(method))
            cerr << "Error: File " << argv[1] << " does not exists!" << endl;
        return EXIT_FAILURE;
    }

    /* Cria um sistema linear e o preenche com informações do arquivo */
    LinearSystem ls;
    is >> ls;

    /* Sequencial */
    if(method == SEQUENTIAL)
    {
        ls.solve(); /* Resolve */
    }
    /* Paralelo */
    else
    {
        /* Distribui as linhas entre os nós */
        Manager::distribute(ls.getOrder());

        /* Mestre executa a checagem */
        if(Manager::getRank() == 0)
            ls.parallelCheck();
        /* Escravos executam os cálculos */
        else
            ls.parallelSolve();

        /* Finaliza o MPI */
        Manager::finalize();
    }

    /* Imprime a saída na tela */
    if(HAS_TO_PRINT(method))
    {
        cout << ls << endl << endl;
        cout << "EXECUTION TIME = " << c.getMiliseconds() << " miliseconds" << endl;
    }

    return EXIT_SUCCESS;
}
